﻿using Flit;
using Irony.Parsing;

namespace Flit
{
    ///<summary>
    /// The irony grammy for Flit
    ///</summary>
    public class FlitGrammar : Grammar
    {
        #region terms that are required for ast discrimination are specified here as class fields

        /// <summary>
        /// the Term for any identifier
        /// </summary>
        internal readonly IdentifierTerminal Identifier;

        /// <summary>
        /// the Term for a list of parameters
        /// </summary>
        internal readonly NonTerminal ParameterList;

        /// <summary>
        /// the Term for a generic (ie, non-label) attribute
        /// </summary>
        internal readonly NonTerminal GenericAttribute;

        #endregion

        /// <summary>
        /// Construct a FlitGrammar
        /// </summary>
        public FlitGrammar()
        {
            //terminals
            Identifier = new IdentifierTerminal("identifier");
            var stringLiteral = new StringLiteral("stringLiteral", "\"");


            //nonterminals
            var graph = new NonTerminal("graph", typeof(Graph));
            var graphItemList = new NonTerminal("graphItemList");
            var graphItem = new NonTerminal("graphItem");
            var state = new NonTerminal("state", typeof(State));
            var transition = new NonTerminal("transition", typeof(Transition));
            var attributes = new NonTerminal("attributes");
            var attributeList = new NonTerminal("attributeList");
            var attribute = new NonTerminal("attribute");
            var labelAttribute = new NonTerminal("labelAttribute", typeof(Label));
            var labelAttributeValue = new NonTerminal("labelAttributeValue");
            GenericAttribute = new NonTerminal("genericAttribute");
            ParameterList = new NonTerminal("parameterList");
            var parameters = new NonTerminal("parameters");
            var parameter = new NonTerminal("parameter");
            var value = new NonTerminal("value");


           

            graph.Rule = "digraph" + Identifier + "{" + graphItemList + "}";
            graphItemList.Rule = MakeStarRule(graphItemList, graphItem);
            graphItem.Rule = (state | transition) + (Empty|";");
            state.Rule = Identifier + attributes;
            transition.Rule = Identifier + "->" + Identifier + attributes;
            attributes.Rule = Empty | ("[" + attributeList + "]");
            attributeList.Rule = MakeStarRule(attributeList, Symbol(","), attribute);
            attribute.Rule = labelAttribute | GenericAttribute;
            labelAttribute.Rule = Symbol("label") + "=" + labelAttributeValue;
            labelAttributeValue.Rule = "\"" + Identifier + parameters + Symbol("\"");


            parameters.Rule = Empty | ("(" + ParameterList + ")");
            ParameterList.Rule = MakeStarRule(ParameterList, Symbol(","), parameter);

            parameter.Rule = Identifier + Identifier;

            GenericAttribute.Rule = Identifier + "=" + value;

            value.Rule = Identifier | stringLiteral;
           

            RegisterPunctuation("{", "}", ";", "[", "]", "->", ",", "=", "\n");
            MarkTransient(graphItemList, graphItem, attributes, value, parameters);

            NonGrammarTerminals.Add(new CommentTerminal("SingleLineComment", "//", "\r", "\n", "\u2085", "\u2028", "\u2029"));
            NonGrammarTerminals.Add(new CommentTerminal("DelimitedComment", "/*", "*/"));

            LanguageFlags = LanguageFlags.CreateAst;
            Root = graph;
        }
    }

}